#include <iostream>
#include <string.h>

#include <stdlib.h>
#include <stdio.h>

#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>


#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include <colores.h>

#include "Producer.hpp"

bool no_more_data, consumemore;
bool producemore, producemoreever;


class ss 
{
public:
    ss():n(-1), use(-1){}
    int n;
    int use; 
    int get1(){return n;};
    int get2(){return use;};
    void print(const char *buf = "")
    {
	printf("#%d (%d)%s", n, use, buf);
    }
};

typedef ss T;

class CProducer2 : public CProducer<T> {
public:

    CProducer2(int capacity) : CProducer<T>(capacity){
    };

    bool start() {
	ss data;
	int i=0;
	do
	{
	    data.n = i++;
	    data.use = -1;
	} while (push_buffer(data));
	return CProducer<T>::start();
    }

    void operator()()
    {
	while (!producemore && !producemoreever && !no_more_data)
	    boost::this_thread::yield(); 
	CProducer<T>::operator()();
    }
    
    bool producer_callback(ss* p_empty)
    {
	if (p_empty->use > 0)
	{
	    printf(" ------------ Producer Error, buffer not empty \n");
	    p_empty->print("------------\n");
	    exit(-1);
	}
	producemore=false;
	while (!producemore && !producemoreever) 
	{
	    p_empty->use = (rand()%2? 83:38);
	    usleep(5000);
	    if (no_more_data)
	    {
		return false;
	    }
	}
	p_empty->use = 88;
	return true;
    }

};

void get_inputs(CProducer2 *buffer, bool *quit);
void print_buffer(CProducer2 *buffer, bool *quit);


void consumer (CProducer2 * buffer, bool *quit)
{
    consumemore = false;
    while (!consumemore && !*quit)
	usleep(100000);

    while (!*quit)
    {
	if (NULL == buffer->consumer())
	    return;
	if (buffer->get_last_used()->use != 88)
	{
	    printf("--------------- Consumer Error, buffer not full -------\n ");
	    exit(-1);
	}
	consumemore = false;
	while (!consumemore && !*quit)
	{
	    buffer->get_last_used()->use = (rand()%2?1:7);
	    usleep(40000);
	}
	buffer->get_last_used()->use = 0;
    }
}

int main(int argc, char *argv[])
{
    no_more_data = false;
    producemore = false;
    producemoreever = false;
    consumemore = false;

    bool quit=false;
    
    CProducer2 buffer(9);
    buffer.start();

    boost::thread th1(print_buffer, &buffer, &quit);
    boost::thread th2(get_inputs, &buffer, &quit);
    consumer(&buffer, &quit);

    quit = true;
    producemoreever = true;
    buffer.stop();
    th2.join();
    th1.join();
    //th.join();

}

void get_inputs(CProducer2 *buffer, bool *quit)
{
    int key =0;
    while (key != 'z' && !*quit)
    {
	//print_buffer(&buffer);
	key = cvWaitKey(100);
	switch (key)
	{
	case 'e':
	    //printf("\nGet one free and put an image on it\n");
	    producemore = true;
	    break;
	case 'c':
	    consumemore = true;//buffer.get_next_used();
	    break;
	case 'q':
	    no_more_data = true;
	}
    }
    producemoreever = true;
    *quit = true;
}


void print_buffer(CProducer2 *buffer, bool *quit)
{
    ss *inuse, *infill;
    ss data;
    char buf[] = "|/-\\";
    static int charbuf=0;
    cvNamedWindow("hola");

    while (!*quit)
    {
	usleep(130000);

	inuse= buffer->get_last_used();
	if (!inuse)
	    inuse = &data;
	infill= buffer->get_last_free();
	if (!infill)
	    infill = &data;
	buffer->CProducer<T>::print(inuse, infill);
	printf("\n");
	printf("InFill (%d): ", buffer->size_queue_free());
	infill->print("\n");
	printf("InUse  (%d): ", buffer->size_queue_used());
	inuse->print("\n");
	printf(" %c \n", buf[charbuf++]);
	charbuf &= 0x3;
    }	    
}
